home *** CD-ROM | disk | FTP | other *** search
/ Mac-Source 1994 July / Mac-Source_July_1994.iso / C and C++ / System / lpDaemon SRC / lpd Sources / Printing.C < prev    next >
Encoding:
C/C++ Source or Header  |  1993-03-15  |  23.0 KB  |  833 lines  |  [TEXT/KAHL]

  1. /************************************************************************
  2.  *                                                                        *
  3.  *    Printing.C                                                            *
  4.  *                                                                        *
  5.  *  Line Printer Daemon using TCP/IP printer protocol                    *
  6.  *                                                                        *
  7.  *            -------------- The printing routines --------------            *
  8.  *                                                                        *
  9.  *  Written by Casper Boon, April, 1992.                                *
  10.  *                                                                        *
  11.  *    © 1992, Casper Boon.                                                *
  12.  *                                                                        *
  13.  * With thanks to Mike Schuster whose article in MacTutor showed how to    *
  14.  * access the PAP code in the LaserWriter.  Also thanks to the CAP team    *
  15.  * at for their PAP code and printer access code.                        *
  16.  *                                                                        *
  17.  * This file contains routines for communicating with the printer using *
  18.  * the Printer Access Protocol (PAP) as well as routines for sending    *
  19.  * a file to a serial printer.  The PAP communication is bi-directional *
  20.  * allowing results to be returned from the printer as well as data     *
  21.  * being sent to the printer.  Serial is on uni-directional so no info    *
  22.  * can be returned.  This is one obvious possible improvement.            *
  23.  *                                                                        *
  24.  * The mechanism in both cases is to request for opening the printer,    *
  25.  * using backgrounder to install a task when connection is made. Then    *
  26.  * a buffer is filled from the file and written to the printer async-    *
  27.  * ronously using backgrounder to call the task repeatedly on completion*
  28.  * to load and send the next buffer until the end of file is reached.    *
  29.  * In the case of the PAP connection a second set of tasks is begun to    *
  30.  * read from the PAP connection until an eond-of-file is received. The    *
  31.  * PAP printing is complete when the end-of-file is received. The serial*
  32.  * printing is complete when the end of file is read in the print file  *
  33.  * and the last buffer has been sent.                                    *
  34.  *                                                                        *
  35.  * The accounting is done only for the PAP printer by sending the page    *
  36.  * count request before starting the print file and reading the result  *
  37.  * from the printer.  This is repeated at the end of the print file     *
  38.  * before sending the end-of-file.  The difference between the results    *
  39.  * should be the number of pages printed.  The only problem is that if     *
  40.  * a print error occurs the printer ignores the rest of the print file    *
  41.  * until the end of file so in this case we need to send the accounting *
  42.  * request after closing the connection so that we can still get the     *
  43.  * number of pages printed before the error occured.  This is where the    *
  44.  * EndPage errors come from.                                            *
  45.  *                                                                        *
  46.  * One other possible enhancement is to add support for SCSI printers.    *
  47.  *                                                                        *
  48.  ************************************************************************/
  49.  
  50. /* include these header files for the types and vars                    */
  51. #include "LPD.H"
  52. #include "PAP.H"
  53. #include "lpdProtos.H"
  54. #include "BackGrounder.H"
  55.  
  56.  
  57.  
  58. #define    F_BUFF_SIZE    4096    /* size of the file read buffer, we send this */
  59.                             /* much to the laser printer so it must be      */
  60.                             /* <= flow_quantum*512 and flow quantum for      */
  61.                             /* the laser writer is 8 so we make it 4K      */
  62. #define SPIN_TIME      20
  63.  
  64.  
  65. typedef struct    {
  66.         LongInt    prt_bytes;            /* number of bytes printed */
  67.         char    rbuff[512];            /* read buffer */
  68.         char    xbuff[F_BUFF_SIZE];    /* file buffer */
  69.         integer    rsize;                /* PAP read size */
  70.         integer    rstate;                /* Status of PAPRead */
  71.         integer    wstate;                /* Status of PAPWrite */
  72.         integer    ostate;                /* Status of PAPOpen */
  73.         integer *prtstate;            /* Pointer to status of print... */
  74.         integer    reof;                /* Set to PAP read EOF status */
  75.         integer    feof;                /* Set when on EOF of print file */
  76.         integer    weof;                /* true when the eof is sent to the printer */
  77.         PAPStatusRec status;        /* pap status */
  78.         integer    pfRef;                /* print file reference number */
  79.         integer    prefnum;            /* pap refNum */
  80.         Handle    entity;                /* Handle to locked entity name */
  81.         Handle    elog;                /* the error log handle */
  82.         integer    count;                /* number of bytes to read from print file */
  83.         integer    last_error;            /* the last recorded error */
  84.         LongInt    prt_size;            /* size of print file */
  85.         LongInt    startpages;            /* page count before printing file */
  86.         LongInt    endpages;            /* page count after printing file */
  87.         Ptr        read_task;
  88.         Boolean    killed;
  89.         Boolean    postscript;
  90.         } PassBlock, *PassPtr;
  91.  
  92.  
  93.  
  94.  
  95. void KillPrinting(integer result, PassPtr passer);
  96. static void DonePrinting(integer result, PassPtr passer);
  97. static void OpenCallBack(integer o_state, Ptr param);
  98. static void WriteCallBack(integer w_state, Ptr param);
  99. static void ReadCallBack(integer w_state, Ptr param);
  100. static void WEOFCallBack(integer r_state, Ptr param);
  101. static void REOFCallBack(integer r_state, Ptr param);
  102.  
  103. static StringPtr PrErrorStatus(Handle entity);
  104. static StringPtr PrForceStatus(Handle entity);
  105. static void LogPrErrorStatus(Handle entity);
  106. static StringPtr PrStatus(Handle entity);
  107. static Handle GenerateEntity(StringPtr printer);
  108. static LongInt ReadPageCount(char *s);
  109. static void ReadProcess(PassPtr passer);
  110. static void GetEndPages(PassPtr passer);
  111.  
  112. static char *account_str =
  113. "(%[ pagecount: ) print statusdict begin pagecount end 20 string cvs print ( ]%\n) print flush\n";
  114.  
  115.  
  116. /************************************************************************
  117.  *                                                                        *
  118.  *                                                                        *
  119.  ************************************************************************/
  120. void PAPDownLoad(integer xRef, Boolean postscript,
  121.                         StringPtr printer, Handle elog, integer *pstate)
  122. {
  123.     integer prErr, pres;
  124.     PassPtr    passer = (PassPtr)NewPtrClear(sizeof(PassBlock));
  125.  
  126.     stopped = FALSE;
  127.  
  128.     passer->reof = FALSE;
  129.     passer->feof = FALSE;
  130.     passer->weof = FALSE;
  131.     passer->pfRef = -1;
  132.     passer->prefnum = -1;
  133.     passer->count = 0;
  134.     passer->last_error = 0;
  135.     passer->read_task = NIL;
  136.     passer->killed = FALSE;
  137.     passer->prtstate = pstate;
  138.     passer->last_error = 0;
  139.     passer->entity = NIL;
  140.     passer->elog = elog;
  141.     passer->startpages = -1;
  142.     passer->endpages = -1;
  143.     *pstate = 1;
  144.  
  145.     passer->prt_bytes = 0L;
  146.     GetEOF(xRef, &passer->prt_size); 
  147.  
  148.     passer->pfRef = xRef;            /* save the reference number globally */
  149.     if (debugOn)
  150.         log_printf("new print file (%d) size %ld\n", passer->pfRef, passer->prt_size);
  151.  
  152.     passer->prefnum = -1;                            /* No connection */
  153.     passer->rstate = 0;
  154.     passer->wstate = 0; passer->ostate = 0;            /* initial states */
  155.     passer->postscript = postscript;
  156.  
  157.     if (passer->entity = PAPLoad())
  158.         {
  159.         if ( printer )
  160.             passer->entity = GenerateEntity(printer);
  161.         else
  162.             HandToHand(&passer->entity);
  163.         HLock(passer->entity);
  164.  
  165.         if (debugOn)
  166.             log_printf("Looking for LaserWriter \"%p:%p@%p\"\n",
  167.                     *passer->entity,
  168.                     *passer->entity+((*passer->entity)[0]+1),
  169.                     *passer->entity+((*passer->entity)[0]+1)+((*passer->entity)[((*passer->entity)[0]+1)]+1));
  170.  
  171.         POPEN_Banner_Up((StringPtr)*(passer->entity), PrForceStatus(passer->entity));
  172.  
  173.         OpenCallBack(-4096, (Ptr)passer);    /* will insert itself in the wait queue */
  174.         }
  175.     else
  176.         {
  177.         log_printf("Cannot Load PAP\n");
  178.         DonePrinting(pres = openErr, passer);
  179.         }
  180. }
  181.  
  182. /************************************************************************
  183.  *                                                                        *
  184.  * Given a pascal string of the form "\pname@LaserWriter:zone" we        *
  185.  * generate a locked EntityName handle for it                            *
  186.  *                                                                        *
  187.  ************************************************************************/
  188. Handle GenerateEntity(StringPtr printer)
  189. {
  190.     Byte    *prt, *ent, old_len, i, j;
  191.     Handle entity;
  192.  
  193.     old_len = printer[0];
  194.     prt = printer;
  195.  
  196.     if ( !(entity = NewHandleClear( sizeof(EntityName) )) )
  197.         return NIL;
  198.  
  199.     HLock(entity);
  200.     ent = (Byte*)*entity;
  201.  
  202.     i = 1; j = 1; prt++;
  203.     while ( (i++ <= old_len) && (*prt != '@') && (*prt != ':') )
  204.         ent[j++] = *prt++;
  205.  
  206.     ent[0] = j - 1; ent += j;
  207.  
  208.     if (*prt != ':' || i > old_len)
  209.         {
  210.         BlockMove("\pLaserWriter", ent, 12);
  211.         ent += 12;
  212.         }
  213.     else
  214.         {
  215.         j = 1; prt++;
  216.         while ( (i++ <= old_len) && (*prt != '@') )
  217.             ent[j++] = *prt++;
  218.  
  219.         ent[0] = j - 1; ent += j;
  220.         }
  221.  
  222.     if (i > old_len)
  223.         BlockMove("\p*", ent, 2);
  224.     else
  225.         {
  226.         j = 1; prt++;
  227.         while (i++ <= old_len)
  228.             ent[j++] = *prt++;
  229.         ent[0] = j - 1;
  230.         }
  231.  
  232.     if (debugOn)
  233.         {
  234.         log_printf("Generated entity \"%p:%p@%p\" for \"%p\"\n",
  235.                 *entity,
  236.                 *entity+((*entity)[0]+1),
  237.                 *entity+((*entity)[0]+1)+((*entity)[((*entity)[0]+1)]+1),
  238.                 printer);
  239.         }
  240.  
  241.     return entity;
  242. }
  243.  
  244. /************************************************************************
  245.  *                                                                        *
  246.  *                                                                        *
  247.  ************************************************************************/
  248. void KillPrinting(integer result, PassPtr passer)
  249. {
  250.     stopped = FALSE;
  251.  
  252.     if (passer->killed)        /* we have already been killed once, abort now */
  253.         return;
  254.  
  255.     log_printf("Print killed......\n");
  256.     passer->last_error = result;
  257.     passer->feof = TRUE;
  258.     passer->killed = TRUE;
  259.  
  260.     if (passer->ostate == noErr)
  261.         {
  262.         PAPClose(passer->prefnum);
  263.         passer->ostate = -1;    /* no longer open */
  264.         }
  265.     passer->reof = TRUE;
  266. }
  267.  
  268. /************************************************************************
  269.  *                                                                        *
  270.  *                                                                        *
  271.  ************************************************************************/
  272. void GetEndPages(PassPtr passer)
  273. {
  274.     OSErr    err;
  275.  
  276.     if (!passer->postscript || !accounting) return;
  277.  
  278.     do    {
  279.         passer->ostate = 1;
  280.         err = PAPOpen(&passer->prefnum, (EntityPtr)*passer->entity, 1,
  281.                                             &passer->status, &passer->ostate);
  282.         if (err != noErr)
  283.             passer->ostate = err;
  284.  
  285.         WaitForState(&passer->ostate);
  286.         }
  287.     while ( passer->ostate == -4096 );
  288.  
  289.     if (passer->ostate < 0)
  290.         {
  291.         log_printf("GetEndPages error %d\n", passer->ostate);
  292.         return;    /* give up */
  293.         }
  294.  
  295.     PAPWrite(passer->prefnum, account_str, strlen(account_str), 1, &passer->wstate);
  296.     WaitForState(&passer->wstate);
  297.  
  298.     passer->rstate = 1;
  299.     do    {
  300.         PAPRead(passer->prefnum, passer->rbuff, &passer->rsize, &passer->reof, &passer->rstate);
  301.  
  302.         WaitForState(&passer->rstate);
  303.  
  304.         ReadProcess(passer);
  305.         }
  306.     while (!passer->reof);
  307.  
  308.     PAPClose(passer->prefnum);
  309. }
  310.  
  311.  
  312.  
  313. /************************************************************************
  314.  *                                                                        *
  315.  *                                                                        *
  316.  ************************************************************************/
  317. void DonePrinting(integer result, PassPtr passer)
  318. {
  319.     if (result > 0) result = 0;
  320.  
  321.     if (passer->entity)
  322.         {
  323.         HUnlock(passer->entity);
  324.         if (passer->ostate == noErr)
  325.             {
  326.             PAPClose(passer->prefnum);
  327.             if (passer->endpages < 0)
  328.                 GetEndPages(passer);
  329.             }
  330.         }
  331.  
  332.     PRT_Banner_Down();    /* will do both (same thing) */
  333.  
  334.     if (passer->endpages > 0)
  335.         log_printf("printed %ld pages\n", passer->endpages-passer->startpages);
  336.     else if (passer->ostate == noErr)
  337.         log_printf("print aborted, couldn't endpage\n");
  338. //    else
  339. //        log_printf("couldn't find printer\n");
  340.  
  341.     *passer->prtstate = result;
  342.  
  343.     DisposPtr( (Ptr) passer );
  344. }
  345.  
  346.  
  347. /************************************************************************
  348.  *                                                                        *
  349.  *                                                                        *
  350.  ************************************************************************/
  351. void OpenCallBack(integer o_state, Ptr param)
  352. {
  353.     integer prErr, pres;
  354.     PassPtr    passer = (PassPtr)param;
  355.  
  356.     if (stopped)    /* we have given up the search */
  357.         {
  358.         DonePrinting(-1, passer);
  359.         return;
  360.         }
  361.  
  362.     if ( o_state > 0 )                                /* we are still waiting */
  363.         {
  364.         POPEN_Banner_Step(PrForceStatus(passer->entity));    /* spin and wait */
  365.         Timeout(&passer->ostate, OpenCallBack, param, SPIN_TIME);
  366.         return;
  367.         }
  368.  
  369.     if ( o_state == -4096 )                                /* printer busy */
  370.         {
  371.         POPEN_Banner_Step((StringPtr)*passer->entity);    /* spin */
  372.         passer->status.statusStr[0] = '\0';        /* Clear status string */
  373.         if ( (pres = PAPOpen(&passer->prefnum, (EntityPtr)*passer->entity, 1,
  374.                                             &passer->status, &passer->ostate)) == noErr )
  375.             Timeout(&passer->ostate, OpenCallBack, param, SPIN_TIME);
  376.         else
  377.             {
  378.             log_printf("Cannot open \"%p:%p@%p\"\n",
  379.                     *passer->entity,
  380.                     *passer->entity+((*passer->entity)[0]+1),
  381.                     *passer->entity+((*passer->entity)[0]+1)+((*passer->entity)[((*passer->entity)[0]+1)]+1));
  382.             passer->postscript = FALSE;
  383.             DonePrinting(pres, passer);
  384.             }
  385.         return;
  386.         }
  387.  
  388.     POPEN_Banner_Down();
  389.     if (o_state == noErr)
  390.         {
  391.         if (debugOn)
  392.             log_printf("Open Status %d \"%p\"\n", passer->ostate, passer->status.statusStr);
  393.  
  394.         PRT_Banner_Up(PrForceStatus(passer->entity));    /* raise the banner */
  395.         ReadCallBack(0, param);
  396.  
  397.         if (passer->postscript && accounting)
  398.             PAPWrite(passer->prefnum, account_str, strlen(account_str), 0, &passer->wstate);
  399.         else
  400.             passer->wstate = 0;
  401.         Background(&passer->wstate, WriteCallBack, param);
  402.         }
  403.     else
  404.         {
  405.         log_printf("Printer open failed; ostate %d\n", passer->ostate);
  406.  
  407.         PrErrorStatus(passer->entity);
  408.         passer->postscript = FALSE;
  409.         DonePrinting(passer->ostate, passer);
  410.         }
  411. }
  412.  
  413.  
  414. /************************************************************************
  415.  *                                                                        *
  416.  *                                                                        *
  417.  ************************************************************************/
  418. void WriteCallBack(integer w_state, Ptr param)
  419. {
  420.     PassPtr    passer = (PassPtr)param;
  421.  
  422.     if (w_state < 0)
  423.         {
  424.         PrErrorStatus(passer->entity);
  425.         KillPrinting(w_state, passer);
  426.         }
  427.     else if (stopped)
  428.         KillPrinting(-1, passer);
  429.     else if (!passer->killed)
  430.         {
  431.         LongInt count = F_BUFF_SIZE;
  432.         passer->feof = FSRead(passer->pfRef, &count, passer->xbuff);
  433.         passer->count = count;
  434.  
  435.         if ( ( passer->feof == noErr ) || ( ( passer->feof == eofErr ) && count ) )
  436.             {    /* either there is no error or we have an end of file
  437.                  * but some bytes have been read */
  438.             if (debugOn)
  439.                 log_printf("Sending %d Bytes\n", passer->count);
  440.  
  441.             PAPWrite(passer->prefnum, passer->xbuff, passer->count, 0, &passer->wstate);
  442.             passer->prt_bytes+=count;
  443.  
  444.             PRT_Banner_PCent( passer->prt_bytes, passer->prt_size , PrStatus(passer->entity) );
  445.  
  446.             Background(&passer->wstate, WriteCallBack, param);
  447.             return;
  448.             }
  449.         }
  450.  
  451.     PRT_Banner_PCent( passer->prt_size, passer->prt_size , PrStatus(passer->entity) );
  452.     PRT_Banner_Down();
  453.     PSTAT_Banner_Up(PrForceStatus(passer->entity));
  454.  
  455.     if (debugOn)
  456.         log_printf("%ld Bytes sent\n", passer->prt_bytes);
  457.  
  458.     /* Exchange EOF messages, then close */
  459.     if (passer->postscript && accounting)
  460.         PAPWrite(passer->prefnum, account_str, strlen(account_str), 1, &passer->wstate);
  461.     else
  462.         PAPWrite(passer->prefnum, NIL, 0, 1, &passer->wstate);
  463.  
  464.     Timeout(&passer->wstate, WEOFCallBack, param, SPIN_TIME);
  465. }
  466.  
  467. /************************************************************************
  468.  *                                                                        *
  469.  *                                                                        *
  470.  ************************************************************************/
  471. void WEOFCallBack(integer w_state, Ptr param)
  472. {
  473.     PassPtr passer = (PassPtr)param;
  474.  
  475.     if (stopped) KillPrinting(-1, passer);
  476.     else if (w_state > 0)    /* we are still waiting */
  477.         {
  478.         PSTAT_Banner_Step(PrStatus(passer->entity));
  479.         if (!passer->killed)
  480.             {
  481.             Timeout(&passer->wstate, WEOFCallBack, param, SPIN_TIME);
  482.             return;
  483.             }
  484.         }
  485.  
  486.     passer->weof = TRUE;
  487.     if (passer->wstate < 0)
  488.         passer->last_error = passer->wstate;
  489.  
  490.     KillBackground(passer->read_task);
  491.     passer->read_task = Timeout(&passer->rstate, REOFCallBack, param, SPIN_TIME);
  492. }
  493.  
  494.  
  495. /************************************************************************
  496.  *                                                                        *
  497.  *                                                                        *
  498.  ************************************************************************/
  499. static void ReadProcess(PassPtr passer)
  500. {
  501.     char     *substr = "%[ pagecount: ", *str;
  502.     LongInt pagecount;
  503.  
  504.     if (passer->rstate < 0)
  505.         PrErrorStatus(passer->entity);
  506.     else if ( passer->rsize > 0 )
  507.         {
  508.         passer->rbuff[passer->rsize] = 0;
  509.  
  510.         if ( str = strstr(passer->rbuff, substr) )    /* look for the "%[ pagecount: " substring */
  511.             {
  512.             str += strlen(substr);
  513.             if (sscanf(str, " %ld", &pagecount) > 0)
  514.                 {
  515.                 if (passer->startpages < 0) passer->startpages = pagecount;
  516.                 else                        passer->endpages = pagecount;
  517.                 }
  518.             }
  519.         else
  520.             {
  521.             log_printf("%s", passer->rbuff);
  522.             LogError(passer->rbuff, passer->elog);
  523.             }
  524.         }
  525. }
  526.  
  527.  
  528. /************************************************************************
  529.  *                                                                        *
  530.  *                                                                        *
  531.  ************************************************************************/
  532. void ReadCallBack(integer r_state, Ptr param)
  533. {
  534.     PassPtr passer = (PassPtr)param;
  535.  
  536.     if (stopped) KillPrinting(-1, passer);
  537.  
  538.     ReadProcess(passer);
  539.  
  540.     /* if last PAPRead finished, try another. */
  541.     if (!passer->killed && !passer->reof)
  542.         {
  543.         PAPRead(passer->prefnum, passer->rbuff, &passer->rsize, &passer->reof, &passer->rstate);
  544.         passer->read_task = Background(&passer->rstate, ReadCallBack, param);
  545.         }
  546. }
  547.  
  548.  
  549. /************************************************************************
  550.  *                                                                        *
  551.  *                                                                        *
  552.  ************************************************************************/
  553. void REOFCallBack(integer r_state, Ptr param)
  554. {
  555.     PassPtr passer = (PassPtr)param;
  556.  
  557.     if (stopped) KillPrinting(-1, passer);
  558.     else if ( r_state > 0 )
  559.         {
  560.         PSTAT_Banner_Step(PrStatus(passer->entity));
  561.         if (!passer->killed)
  562.             {
  563.             passer->read_task = Timeout(&passer->rstate, REOFCallBack, param, SPIN_TIME);
  564.             return;
  565.             }
  566.         else
  567.             passer->reof = TRUE;
  568.         }
  569.     else
  570.         ReadProcess(passer);
  571.  
  572.     if (!passer->reof)
  573.         {
  574.         if (PAPRead(passer->prefnum, passer->rbuff, &passer->rsize, &passer->reof, &passer->rstate) == noErr)
  575.             passer->read_task = Timeout(&passer->rstate, REOFCallBack, param, SPIN_TIME);
  576.         return;
  577.         }
  578.  
  579.     DonePrinting(passer->last_error, passer);
  580. }
  581.  
  582. /************************************************************************
  583.  *                                                                        *
  584.  *                                                                        *
  585.  ************************************************************************/
  586.  
  587. static LongInt        next_stat = 0;
  588. static PAPStatusRec    status;
  589.  
  590. /************************************************************************
  591.  *                                                                        *
  592.  *                                                                        *
  593.  ************************************************************************/
  594. static StringPtr PrStatus(Handle entity)
  595. {
  596.     AddrBlock    node;
  597.  
  598.     if (Ticks < next_stat)
  599.         return NIL;
  600.  
  601.     next_stat = Ticks + 1200;            /* every 20 seconds    */
  602.     status.statusStr[0] = '\0';         /* Clear status string */
  603.     node.aNet = 0;
  604.     node.aNode = 0;
  605.     node.aSocket = 0;
  606.  
  607.     PAPStatus((EntityPtr)*entity, &status, &node);
  608.  
  609.     return status.statusStr;
  610. }
  611.  
  612.  
  613. /************************************************************************
  614.  *                                                                        *
  615.  *                                                                        *
  616.  ************************************************************************/
  617. static StringPtr PrErrorStatus(Handle entity)
  618. {
  619.     StringPtr tmp;
  620.     next_stat = 0;    /* to force an update */
  621.     tmp = PrStatus(entity);
  622.     next_stat = 0;    /* to force an update next time */
  623.  
  624.     return tmp;
  625. }
  626.  
  627. /************************************************************************
  628.  *                                                                        *
  629.  *                                                                        *
  630.  ************************************************************************/
  631. StringPtr PrinterStatus(StringPtr printer)
  632. {
  633.     StringPtr tmp;
  634.     Handle      entity;
  635.  
  636.     entity = GenerateEntity(printer);
  637.  
  638.     next_stat = 0;    /* to force an update */
  639.     tmp = PrStatus(entity);
  640.     next_stat = 0;    /* to force an update next time */
  641.  
  642.     HUnlock(entity);
  643.     DisposHandle(entity);
  644.  
  645.     return tmp;
  646. }
  647.  
  648. /************************************************************************
  649.  *                                                                        *
  650.  *                                                                        *
  651.  ************************************************************************/
  652. static StringPtr PrForceStatus(Handle entity)
  653. {
  654.     next_stat = 0;    /* to force an update */
  655.     return PrStatus(entity);
  656. }
  657.  
  658.  
  659. /************************************************************************
  660.  *                                                                        *
  661.  *                                                                        *
  662.  ************************************************************************/
  663. static Str255 aPrName;
  664.  
  665. StringPtr GetPRName(void);
  666. StringPtr GetPRName()
  667. {
  668.     integer    LWref;
  669.     integer wdRef;
  670.     LongInt wdID;
  671.     integer vol;
  672.     SignedByte state;
  673.     extern Str255 LaserWriterName;
  674.  
  675.     Handle    entHndl;
  676.  
  677.     GetWDir(&wdRef, &wdID, &vol);
  678.     SetExtnsFolder();
  679.  
  680.     if ( (LWref = OpenResFile(LaserWriterName)) == -1 )
  681.         {
  682.         SetWDir(wdRef, wdID, vol);
  683.         return NIL;
  684.         }
  685.  
  686.     if ( ( entHndl = GetResource('PAPA', -8192) ) == NIL || ResError() )
  687.         {
  688.         CloseResFile(LWref);
  689.         SetWDir(wdRef, wdID, vol);
  690.         return NIL;
  691.         }
  692.  
  693.     state = HGetState(entHndl);
  694.     HLock(entHndl);
  695.  
  696.     psprintf(aPrName, "\"%p:%p@%p\"",
  697.         *entHndl,
  698.         *entHndl+((*entHndl)[0]+1),
  699.         *entHndl+((*entHndl)[0]+1)+((*entHndl)[((*entHndl)[0]+1)]+1));
  700.  
  701.     HSetState(entHndl, state);
  702.  
  703.     CloseResFile(LWref);
  704.     SetWDir(wdRef, wdID, vol);
  705.  
  706.     return aPrName;
  707. }
  708.  
  709. /************************************************************************
  710.  *                                                                        *
  711.  *                                                                        *
  712.  ************************************************************************/
  713.  
  714. #include <Serial.H>
  715. pascal OSErr RAMSDOpen(SPortSel sPort);
  716. pascal void RAMSDClose(SPortSel sPort);
  717.  
  718. typedef struct IOPassBlock
  719.     {
  720.     integer    *iostate;
  721.     IOParam    iorec;
  722.     } IOPassBlock, *IOPassPtr;
  723.  
  724.  
  725. static void SerialWCallBack(integer w_state, Ptr param);
  726. static integer SerialWrite(integer sRef, Ptr data, integer count, integer *wstate);
  727. static void SWriteCallBack(integer w_state, Ptr param);
  728.  
  729.  
  730. /************************************************************************
  731.  *                                                                        *
  732.  *                                                                        *
  733.  ************************************************************************/
  734. void SerialPrint(integer xRef, Boolean postscript,
  735.                             StringPtr printer, Word params,
  736.                                     Handle elog, integer *pstate)
  737. {
  738.     PassPtr    parms = (PassPtr)NewPtrClear(sizeof(PassBlock));
  739.  
  740.     *pstate = 1;
  741.     parms->prtstate = pstate;
  742.  
  743.     if (debugOn)
  744.         log_printf("new serial print file (%d)\n", parms->pfRef);
  745.  
  746.     RAMSDOpen(sPortA);
  747.     parms->prefnum = aoutRefNum;
  748.  
  749.     parms->killed = FALSE;
  750.     stopped = FALSE;
  751.     parms->prt_bytes = 0L;
  752.     parms->pfRef = xRef;
  753.  
  754.     SWriteCallBack(0, (Ptr)parms);
  755. }
  756.  
  757. /************************************************************************
  758.  *                                                                        *
  759.  *                                                                        *
  760.  ************************************************************************/
  761. integer SerialWrite(integer sRef, Ptr data, integer count, integer *wstate)
  762. {
  763.     IOPassPtr    iop = (IOPassPtr)NewPtrClear(sizeof(IOPassBlock));
  764.     IOParam        *parm = (IOParam*)&iop->iorec;
  765.  
  766.     *wstate = 1;
  767.     iop->iostate = wstate;
  768.     parm->ioCompletion = NIL;
  769.     parm->ioRefNum = sRef;
  770.     parm->ioBuffer = data;
  771.     parm->ioReqCount = count;
  772.     parm->ioPosMode = 0;
  773.     parm->ioPosOffset = 0;
  774.  
  775.     PBWrite((ParmBlkPtr)parm, TRUE);
  776.     Background(&parm->ioResult, SerialWCallBack, (Ptr)iop);
  777. }
  778.  
  779. /************************************************************************
  780.  *                                                                        *
  781.  *                                                                        *
  782.  ************************************************************************/
  783. void SerialWCallBack(integer w_state, Ptr param)
  784. {
  785.     IOPassPtr    iop = (IOPassPtr)param;
  786.     IOParam        *parm = (IOParam*)&iop->iorec;
  787.  
  788.     *iop->iostate = w_state;
  789.     DisposPtr((Ptr)iop);
  790. }
  791.  
  792.  
  793. /************************************************************************
  794.  *                                                                        *
  795.  *                                                                        *
  796.  ************************************************************************/
  797. void SWriteCallBack(integer w_state, Ptr param)
  798. {
  799.     PassPtr    parms = (PassPtr)param;
  800.  
  801.     if (stopped)
  802.         KillPrinting(-1, parms);
  803.     else if (!parms->killed)
  804.         {
  805.         LongInt count = F_BUFF_SIZE;
  806.         parms->feof = FSRead(parms->pfRef, &count, parms->xbuff);
  807.         parms->count = count;
  808.  
  809.         if ( ( parms->feof == noErr ) || ( ( parms->feof == eofErr ) && parms->count ) )
  810.             {    /* either there is no error or we have an end of file
  811.                  * but some bytes have been read */
  812.             if (debugOn)
  813.                 log_printf("Sending %ld Bytes\n", parms->count);
  814.  
  815.             SerialWrite(parms->prefnum, parms->xbuff, parms->count, &parms->wstate);
  816.             parms->prt_bytes+=parms->count;
  817.  
  818.             Background(&parms->wstate, SWriteCallBack, (Ptr)parms);
  819.             return;
  820.             }
  821.         }
  822.  
  823.     if (debugOn)
  824.         log_printf("%ld Bytes sent\n", parms->prt_bytes);
  825.  
  826.     FSClose(parms->pfRef);
  827.     RAMSDClose(sPortA);
  828.  
  829.     *parms->prtstate = 0;
  830.  
  831.     DisposPtr((Ptr)parms);
  832. }
  833.